﻿// Copyright (c) 2008, Colin Burn
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 
// * Neither the name of WTCL nor the names of its contributors may be
// used to endorse or promote products derived from this software
// without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;

using WTCL.Charts.Axis.Data;
using WTCL.Charts.Axis.Ticks;
using WTCL.Data.Series;
using WTCL.Data.Series.Interface;

namespace WTCL.Charts.Axis.Scale
{
    public class GroupXAxisScale<TSeries, TData, TChart, TChartCanvas> : AxisScale<TChart, GroupAxisData, XAxisTick>
        where TSeries : SeriesBase<TData>, IGroupXAxisSeries
        where TData : INamedData
        where TChart : Chart<TSeries, TData, TChart, TChartCanvas>
        where TChartCanvas : BaseChartCanvas<TSeries, TData, TChart, TChartCanvas>
    {
        private int maxGroups;

        internal GroupXAxisScale()
        {
        }

        protected override List<List<XAxisTick>> UpdateTickMarks()
        {
            List<List<XAxisTick>> ret = new List<List<XAxisTick>>();

            Typeface typeface = new Typeface(this.Chart.ChartCanvas.FontFamily, this.Chart.ChartCanvas.FontStyle, this.Chart.ChartCanvas.FontWeight, this.Chart.ChartCanvas.FontStretch);

            int numberOfLables = this.maxGroups;

            // How many group labels can I display?
            foreach (TSeries series in this.Chart.Series)
            {
                // Find the height of a typical label.
                FormattedText label = new FormattedText(series.LargestDisplayXValue, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, this.Chart.ChartCanvas.FontSize, this.Brush);

                numberOfLables = Math.Min(numberOfLables, (int)Math.Floor(this.Chart.ActualWidth / (label.Width * 1.5)));
            }

            if (numberOfLables > 0)
            {
                int spacing = this.maxGroups / numberOfLables;

                foreach (TSeries series in this.Chart.Series)
                {
                    List<XAxisTick> axisData = new List<XAxisTick>();

                    for (int i = 0; i < series.Samples.Count; i += spacing)
                    {
                        double position = (i + 0.5) * (this.Chart.ChartCanvas.ActualWidth / maxGroups);
                        FormattedText label = new FormattedText(series.Samples[i].Name, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, this.Chart.ChartCanvas.FontSize, this.Brush);

                        axisData.Add(new XAxisTick(label, position));
                    }

                    ret.Add(axisData);
                }
            }

            return ret;
        }

        protected override List<GroupAxisData> UpdateAxisData()
        {
            List<GroupAxisData> ret = new List<GroupAxisData>();

            this.maxGroups = 0;

            foreach (TSeries series in this.Chart.Series)
            {
                GroupAxisData axisData = new GroupAxisData();

                foreach (TData data in series.Samples)
                {
                    axisData.Names.Add(data.Name);
                }

                ret.Add(axisData);

                this.maxGroups = Math.Max(this.maxGroups, series.Samples.Count);
            }

            return ret;
        }

        internal double GetPosition(int groupIndex, double actualWidth)
        {
            UpdateAxisData();

            double groupWidth = actualWidth / maxGroups;

            return (groupIndex + 0.5) * groupWidth;
        }
    }
}
